package com.xiaojie.note;

/**
 * @Description:笔记
 * @author: yan
 * @date: 2021.10.25
 */
public class Note {
    /*
        partition：
        topic:

     */

    /*
        1、与大多数分布式系统一样，自动处理故障需要精确定义节点 “alive” 的概念。Kafka 判断节点是否存活有两种方式。
            节点必须可以维护和 ZooKeeper 的连接，Zookeeper 通过心跳机制检查每个节点的连接。
            如果节点是个 follower ，它必须能及时的同步 leader 的写操作，并且延时不能太久。
        2、 只有当消息被所有的副本节点加入到日志中时, 才算是提交, 只有提交的消息才会被 consumer 消费,
        这样就不用担心一旦 leader 挂掉了消息会丢失。另一方面， producer 也 可以选择是否等待消息被提交，
        这取决他们的设置在延迟时间和持久性之间的权衡，这个选项是由 producer 使用的 acks（0,1，-1） 设置控制。
        3、pacificA副本数据使用主从式框架来保证数据一致性。分片的多个副本中存在一个主副本Primary和多个从副本Secondary。
        所有的数据更新和读取都进入主副本，当主副本出现故障无法访问时系统会从其他从副本中选择合适的节点作为新的主。
        在pacificA协议中，每个节点都维护
        数据更新的流程如下：
            1、更新记录进入主副本节点处理，为该记录分配Sn（Serial Number），然后将该记录插入prepare list，该list上的记录按照sn有序排列；
            2、主副本节点将携带sn的记录发往从节点，从节点同样将该记录插入到prepare list；
            3、一旦主节点收到所有从节点的响应，确定该记录已经被正确写入所有的从节点，那就将commit list向前移动，并将这些消息应用到主节点的状态机；
            4、主节点提交后即可给客户端返回响应，同时向所有从节点发送消息，告诉从节点可以提交刚刚写入的记录了
         所有的读需要全部发往主节点，这是因为客户端来读时，主节点有可能尚未将commit消息发送至从，因此，如果读从节点可能会无法获取最新数据。当然，如果应用能够忍受一定的窗口，那读从也无所谓。
         4、 Kafka 采取了一种稍微不同的方法来选择它的投票集。 Kafka 不是用大多数投票选择 leader 。
            Kafka 动态维护了一个同步状态的备份的集合 （a set of in-sync replicas）， 简称 ISR ，
            在这个集合中的节点都是和 leader 保持高度一致的，只有这个集合的成员才 有资格被选举为 leader，
            一条消息必须被这个集合 所有 节点读取并追加到日志中了，这条消息才能视为提交
         5、请注意，Kafka 对于数据不会丢失的保证，是基于至少一个节点在保持同步状态，一旦分区上的所有备份节点都挂了，就无法保证了。
            但是，实际在运行的系统需要去考虑假设一旦所有的备份都挂了，怎么去保证数据不会丢失，这里有两种实现的方法

                等待一个 ISR 的副本重新恢复正常服务，并选择这个副本作为领 leader （它有极大可能拥有全部数据）。
                选择第一个重新恢复正常服务的副本（不一定是 ISR 中的）作为leader。
             可用性和数据一致性的妥协保证AC
         6、 向 Kafka 写数据时，producers 设置 ack 是否提交完成， 0：不等待broker返回确认消息,1: leader保存成功返回或, -1(all): 所有备份都保存成功返回.请注意.
            设置 “ack = all” 并不能保证所有的副本都写入了消息。默认情况下，当 acks = all 时，只要 ISR 副本同步完成，就会返回消息已经写入。
            例如，一个 topic 仅仅设置了两个副本，那么只有一个 ISR 副本，那么当设置acks = all时返回写入成功时，剩下了的那个副本数据也可能数据没有写入。
         7、卡夫卡的备份管理
         我们会选择一个 broker 作为 “controller”节点。
         controller 节点负责 检测 brokers 级别故障,并负责在 broker 故障的情况下更改这个故障 Broker 中的 partition 的 leadership 。
         这种方式可以批量的通知主从关系的变化，使得对于拥有大量partition 的broker ,选举过程的代价更低并且速度更快。
         如果 controller 节点挂了，其他 存活的 broker 都可能成为新的 controller 节点。
     */



    /***************************************************************************************************************************/
    /*
    https://blog.csdn.net/qq_26838315/article/details/106883256
1、	topic : my-topic-partition

	partition1：{"controller_epoch":4,"leader":1,"version":1,"leader_epoch":0,"isr":[1,3,2]}
	partition2：{"controller_epoch":4,"leader":2,"version":1,"leader_epoch":0,"isr":[2,1,3]}
	partition3：{"controller_epoch":4,"leader":3,"version":1,"leader_epoch":0,"isr":[3,2,1]}
	partition4：{"controller_epoch":4,"leader":1,"version":1,"leader_epoch":0,"isr":[1,2,3]}
	partition5：{"controller_epoch":4,"leader":2,"version":1,"leader_epoch":0,"isr":[2,3,1]}
	partition6：{"controller_epoch":4,"leader":3,"version":1,"leader_epoch":0,"isr":[3,1,2]}

	其中controller_epoch表示的是当前的kafka控制器，leader表示当前分区的leader副本所在的broker的id编号，version表示版本号，
	（当前半本固定位1），leader_epoch表示当前分区的leader纪元，isr表示变更后的isr列表。


2、HW：ISR与HW和LEO也有紧密的关系，HW是High Watermak的缩写， 俗称高水位，
     它表示了一个特定消息的偏移量（offset），消费之只能拉取到这个offset之前的消息。
    LEO：LEO是Log End Offset的缩写，它表示了当前日志文件中下一条待写入消息的offset，
            如上图offset为9的位置即为当前日志文件LEO,LEO的大小相当于当前日志分区中最后一条消息的offset值加1。
            分区ISR集合中的每个副本都会维护自身的LEO，而ISR集合中最小的LEO即为分区的HW，
            对消费这而言只能消费HW之前的消息。
	LW:是Low Watermark的缩写，俗称“低水位”，代表AR集合中最小的logStartOffset值，
	 副本的拉取请求（FetchRequest，它有可能触发新建日志分段而旧的的被清理，进而导致logStartoffset的增加）和删除请求（DeleteRecordRequest）都可能促使LW的增长。


3、由此可见,kafka的复制机制不是完全的同步复制，也不是单纯的异步复制，事实上，
        同步复制要求所有能工作的Follower副本都复制完，这条消息才会被确认为成功提交，
        这种复制方式影响了性能。而在异步复制的情况下， follower副本异步地从leader副本中复制数据，
        数据只要被leader副本写入就被认为已经成功提交。在这种情况下，如果follower副本都没有复制完而落后于leader副本，
        如果突然leader副本宕机，则会造成数据丢失。Kafka使用这种ISR的方式有效的权衡了数据可靠性与性能之间的关系。

4、	简单来说，分区中的所有副本统称为 AR (Assigned Replicas)。
	所有与leader副本保持一定程度同步的副本（包括leader副本在内）组成 ISR (In Sync Replicas)。
	 ISR 集合是 AR 集合的一个子集。消息会先发送到leader副本，然后follower副本才能从leader中拉取消息进行同步。
	同步期间，follow副本相对于leader副本而言会有一定程度的滞后。
	前面所说的 ”一定程度同步“ 是指可忍受的滞后范围，这个范围可以通过参数进行配置。
	于leader副本同步滞后过多的副本（不包括leader副本）将组成 OSR （Out-of-Sync Replied）由此可见，AR = ISR + OSR。
	正常情况下，所有的follower副本都应该与leader 副本保持 一定程度的同步，即AR=ISR，OSR集合为空。

5、由于生产者生产的消息会不断追加到log文件末尾，为防止log文件过大导致数据定位效率低下，Kafka采取了分片和索引机制，
将每个partition分为多个segment(逻辑概念，等于index+log文件)。

每个partition(目录)相当于一个巨型文件被平均分配到多个大小相等的segment(片段)数据文件中（每个segment文件中消息数量不一定相等），
这种特性也方便old segment的删除，即方便已被消费的消息的清理，提高磁盘的利用率。每个partition只需要支持顺序读写就行，
segment的文件生命周期由服务端配置参数（log.segment.bytes，log.roll.{ms,hours}等若干参数）决定。


6、每个segment对应两个文件——“.index”文件和“.log”文件。分别表示为segment索引文件和数据文件（引入索引文件的目的就是便于利用二分查找快速定位message位置）。
这两个文件的命令规则为：partition全局的第一个segment从0开始，后续每个segment文件名以当前segment的第一条消息的offset命名，数值大小为64位，20位数字字符长度，没有数字用0填充。

这些文件位于一个文件夹下（partition目录），该文件夹的命名规则为：topic名称+分区序号。例如，first这个topic有三个分区，则其对应的文件夹为first-0,first-1,first-2。


7、如何根据offset获取数据
第一步：查找Segment File.

00000000000000000000.index表示最开始的文件，起始偏移量（offset）为0；第二个文件00000000000000368770.index的起始偏移量为368770，依次类推。
以起始偏移量命名并排序这些文件，只要根据offset二分查找文件列表，就可以快速定位到具体文件。

当offset=368776时，定位到00000000000000368770.index|log。


第二步：通过Segment File 查找Message。

通过第一步定位到Segment File,当offset=368776时，依次定位到00000000000000368770.index的元数据物理位置和00000000000000368770.log的物理偏移地址，
然后再通过00000000000000368770.log顺序查找，直到offset=368776为止。

Segment Index File采取稀疏索引存储方式，可以减少索引文件大小，通过Linux mmap接口可以直接进行内存操作。
稀疏索引为数据文件的每个对应Message设置一个元数据指针，它比稠密索引节省了更多的存储空间，但查找起来需要消耗更多的时间。

8、分区 Leader 选举策略有几种?
当前，Kafka 有 4 种分区 Leader 选举策略。

OfflinePartition Leader 选举:每当有分区上线时，就需要执行 Leader 选举。
所谓的分区上线，可能是创建了新分区，也可能是之前的下线分区重新上线。这是最常见的分区 Leader 选举场景。

ReassignPartition Leader 选举:当你手动运行 kafka-reassign-partitions 命令，或者是调用 Admin 的 alterPartitionReassignments 方法执行分区副本重分配时，
可能触发此类选举。假设原来的 AR 是[1，2，3]，Leader 是 1，当执行副本重分配后，副本集 合 AR 被设置成[4，5，6]，显然，
Leader 必须要变更，此时会发生 Reassign Partition Leader 选举。

PreferredReplicaPartition Leader 选举:当你手动运行 kafka-preferred-replica- election 命令，或自动触发了 Preferred Leader 选举时，该类策略被激活。
所谓的 Preferred Leader，指的是 AR 中的第一个副本。比如 AR 是[3，2，1]，那么， Preferred Leader 就是 3。

ControlledShutdownPartition Leader 选举:当 Broker 正常关闭时，该 Broker 上 的所有 Leader 副本都会下线，因此，需要为受影响的分区执行相应的 Leader 选举。

这 4 类选举策略的大致思想是类似的，即从 AR 中挑选首个在 ISR 中的副本，作为新 Leader。
当然，个别策略有些微小差异。不过，回答到这种程度，应该足以应付面试官 了。毕竟，微小差别对选举 Leader 这件事的影响很小。

9、 Follower 副本消息同步的完整流程
首先，Follower 发送 FETCH 请求给 Leader。
接着，Leader 会读取底层日志文件中的消 息数据，再更新它内存中的 Follower 副本的 LEO 值，更新为 FETCH 请求中的 fetchOffset 值。
最后，尝试更新分区高水位值。Follower 接收到 FETCH 响应之后，会把 消息写入到底层日志，接着更新 LEO 和 HW 值。

Leader 和 Follower 的 HW 值更新时机是不同的，Follower 的 HW 更新永远落后于 Leader 的 HW。这种时间上的错配是造成各种不一致的原因。

10、LEO:Log End Offset。日志末端位移值或末端偏移量，表示日志下一条待插入消息的 位移值。举个例子，如果日志有 10 条消息，位移值从 0 开始，那么，第 10 条消息的位 移值就是 9。此时，LEO = 10。
LSO:Log Stable Offset。这是 Kafka 事务的概念。如果你没有使用到事务，那么这个 值不存在(其实也不是不存在，只是设置成一个无意义的值)。该值控制了事务型消费 者能够看到的消息范围。它经常与 Log Start Offset，即日志起始位移值相混淆，因为 有些人将后者缩写成 LSO，这是不对的。在 Kafka 中，LSO 就是指代 Log Stable Offset。
AR:Assigned Replicas。AR 是主题被创建后，分区创建时被分配的副本集合，副本个 数由副本因子决定。
ISR:In-Sync Replicas。Kafka 中特别重要的概念，指代的是 AR 中那些与 Leader 保 持同步的副本集合。在 AR 中的副本可能不在 ISR 中，但 Leader 副本天然就包含在 ISR 中。关于 ISR，还有一个常见的面试题目是如何判断副本是否应该属于 ISR。目前的判断 依据是:Follower 副本的 LEO 落后 Leader LEO 的时间，是否超过了 Broker 端参数 replica.lag.time.max.ms 值。如果超过了，副本就会被从 ISR 中移除。
HW:高水位值(High watermark)。这是控制消费者可读取消息范围的重要字段。一 个普通消费者只能“看到”Leader 副本上介于 Log Start Offset 和 HW(不含)之间的 所有消息。水位以上的消息是对消费者不可见的。
     */
}
